1 /*
2 * Copyright (C) 2013 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.google.common.reflect;
18
19 import com.google.common.collect.Sets;
20
21 import java.lang.reflect.GenericArrayType;
22 import java.lang.reflect.ParameterizedType;
23 import java.lang.reflect.Type;
24 import java.lang.reflect.TypeVariable;
25 import java.lang.reflect.WildcardType;
26 import java.util.Set;
27
28 import javax.annotation.concurrent.NotThreadSafe;
29
30 /**
31 * Based on what a {@link Type} is, dispatch it to the corresponding {@code visit*} method. By
32 * default, no recursion is done for type arguments or type bounds. But subclasses can opt to do
33 * recursion by calling {@link #visit} for any {@code Type} while visitation is in progress. For
34 * example, this can be used to reject wildcards or type variables contained in a type as in:
35 *
36 * <pre> {@code
37 * new TypeVisitor() {
38 * protected void visitParameterizedType(ParameterizedType t) {
39 * visit(t.getOwnerType());
40 * visit(t.getActualTypeArguments());
41 * }
42 * protected void visitGenericArrayType(GenericArrayType t) {
43 * visit(t.getGenericComponentType());
44 * }
45 * protected void visitTypeVariable(TypeVariable<?> t) {
46 * throw new IllegalArgumentException("Cannot contain type variable.");
47 * }
48 * protected void visitWildcardType(WildcardType t) {
49 * throw new IllegalArgumentException("Cannot contain wildcard type.");
50 * }
51 * }.visit(type);}</pre>
52 *
53 * <p>One {@code Type} is visited at most once. The second time the same type is visited, it's
54 * ignored by {@link #visit}. This avoids infinite recursion caused by recursive type bounds.
55 *
56 * <p>This class is <em>not</em> thread safe.
57 *
58 * @author Ben Yu
59 */
60 @NotThreadSafe
61 abstract class TypeVisitor {
62
63 private final Set<Type> visited = Sets.newHashSet();
64
65 /**
66 * Visits the given types. Null types are ignored. This allows subclasses to call
67 * {@code visit(parameterizedType.getOwnerType())} safely without having to check nulls.
68 */
69 public final void visit(Type... types) {
70 for (Type type : types) {
71 if (type == null || !visited.add(type)) {
72 // null owner type, or already visited;
73 continue;
74 }
75 boolean succeeded = false;
76 try {
77 if (type instanceof TypeVariable) {
78 visitTypeVariable((TypeVariable<?>) type);
79 } else if (type instanceof WildcardType) {
80 visitWildcardType((WildcardType) type);
81 } else if (type instanceof ParameterizedType) {
82 visitParameterizedType((ParameterizedType) type);
83 } else if (type instanceof Class) {
84 visitClass((Class<?>) type);
85 } else if (type instanceof GenericArrayType) {
86 visitGenericArrayType((GenericArrayType) type);
87 } else {
88 throw new AssertionError("Unknown type: " + type);
89 }
90 succeeded = true;
91 } finally {
92 if (!succeeded) { // When the visitation failed, we don't want to ignore the second.
93 visited.remove(type);
94 }
95 }
96 }
97 }
98
99 void visitClass(Class<?> t) {}
100 void visitGenericArrayType(GenericArrayType t) {}
101 void visitParameterizedType(ParameterizedType t) {}
102 void visitTypeVariable(TypeVariable<?> t) {}
103 void visitWildcardType(WildcardType t) {}
104 }